home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1992
/
04
/
btc.asc
< prev
next >
Wrap
Text File
|
1992-03-10
|
9KB
|
293 lines
_BLOCK TRUNCATION COMPRESSION_
by Anton Kruger
[LISTING ONE]
/* File: btc4x4.c -- Author: Anton Kruger -- Revision: 1.0
* Copyright (c) Truda Software
* 215 Marengo Rd, #2, Oxford, IA 52322-9383
* Description: Contains routines for performing 4x4 block truncation
* compression on 8-bit, 256x256 monochrome images.
* Compilers: MSC 5.1.
*/
/* *** Headers *** */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* *** Typedefs and defines *** */
typedef unsigned char byte;
typedef unsigned int word;
#define IOBUFFSIZE 2048 /* size of i/o buffers */
/* *** Function prototypes *** */
void main(int argc, char *argv[]);
void btc4x4(FILE *fp1, FILE * fp2);
void GetStats(byte * block,byte *a,byte *b,byte *mean);
int GetBlock(byte *block, FILE *fp);
void PutCode(byte a, byte b, word code, FILE *fp);
void inform(char *mess);
void main(int argc, char *argv[])
{
/* A short driver routine for "btc4x4.c", that performs block truncation
** compression on an image file. */
FILE *fp1,*fp2;
if (argc < 3){
inform("Usage: BTC4x4 infile outfile\n\n");
inform("infile is a 256x256 binary image file\n");
inform("outfile is a BTC-compressed file\n");
exit(-1);
}
if ((fp1 = fopen(argv[1],"rb")) == NULL) {
inform("ERROR: Could not open input file: ");
inform(argv[1]);
exit(-1);
}
setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE);
if ((fp2 = fopen(argv[2],"wb")) == NULL) {
inform("ERROR: Could not open output file: ");
inform(argv[2]);
exit(-1);
}
setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE);
inform("Block Truncation Compression.\n");
inform(argv[1]); inform(" -> "); inform(argv[2]);
inform("\nPlease wait...\n");
btc4x4(fp1, fp2);
fclose(fp1);
fclose(fp2);
inform("Done!\n");
exit(0);
}
void btc4x4(FILE *fp1, FILE * fp2)
{
/* Block truncation compress the file connected to "fp1". The output goes
** to the file connected to "fp2". */
int i;
byte a,b,mean;
byte block[16];
word code;
while (GetBlock(block,fp1) != EOF){
GetStats(block,&a,&b,&mean);
code = 0; /* clear bits */
for (i=0;i<=15;i++)
if (block[i] >= mean)
code = code | (1<<i); /* set bit "i" */
PutCode(a,b,code,fp2);
}
}
void GetStats(byte * block,byte *a,byte *b,byte *mean)
{
/* This routine computes the statistics "a", "b", and "mean" for the pixels
** in "block". */
int i,q;
float m1,m2,sigma;
float atmp,btmp;
double d;
/* Compute mean, mean-square, and "sigma". */
m1 = m2 = (float)0.0;
for (i=0;i<=15;i++){
m1 = m1 + (float)block[i];
m2 = m2 + (float)(block[i]*block[i]);
}
m1 = m1/16.0;
m2 = m2/16.0;
sigma = (float)sqrt((double)(m2- m1*m1));
/* Count "q", the number of pixels >= "mean" , then compute "a", and "b". */
for (q=0,i=0;i<=15;i++)
if ((float)block[i] >= m1) q++;
if (q == 16){
*mean = (byte)(m1+0.5);
*a = *b = *mean; /* all pixels are the same */
}
else{
d = sqrt((double)q/(16.0-q));
atmp = m1 - sigma*d;
btmp = m1 + sigma/d;
if (atmp < (float)0) atmp = (float)0;
if (btmp > (float)255) btmp = (float)255;
/* Round values to nearest integer */
*a = (byte)(0.5+atmp);
*b = (byte)(0.5+btmp);
*mean = (byte)(m1+0.5);
}
}
int GetBlock(byte *block, FILE *fp)
{
/* This routine gets a block of 4x4 pixels from the file connected to "fp".
** Normally it returns 1. If at EOF, or errors occur, it returns EOF. */
static int bp = 256;
static byte buffer[4][256];
int i,j;
/* If the 4-line buffer is empty, fill it. If it cannot be filled for some
** reason, return EOF. Otherwise, reset the buffer pointer "bp". */
if (bp == 256){
for (j=0;j<=3;j++)
if (fread(buffer[j],1,256,fp) != 256)
return(EOF);
bp = 0;
}
/* Get 16 pixels from the 4-line buffer. Then update the buffer
** pointer "bp", and return to caller. */
for (j=0;j<=3;j++)
for (i=0;i<=3;i++)
block[i+4*j] = buffer[j][bp+i];
bp = bp+4;
return(1);
}
void PutCode(byte a, byte b, word code, FILE *fp)
{
/* This routine writes "a", "b", and the block truncation "code" to
** the file connected to "fp". */
fputc((byte)a,fp);
fputc((byte)b,fp);
fputc((byte)(code & 255),fp); /* LSB first */
fputc((byte)((code>>8) & 255),fp); /* MSB second */
}
void inform(char *mess)
{
fprintf(stderr,"%s",mess);
}
[LISTING TWO]
/* File: btd4x4.c -- Author: Anton Kruger -- Revision: 1.0
* Copyright (c) Truda Software
* 215 Marengo Rd, #2, Oxford, IA 52322-9383
* Description: Contains routines for performing 4x4 block truncation
* decompression; assumes input files were compressed with "btc4x4".
* Compilers: MSC 5.1.
*/
/* *** Headers *** */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* *** Typedefs and defines *** */
typedef unsigned char byte;
typedef unsigned int word;
#define IOBUFFSIZE 2048 /* size of i/o buffers */
/* *** Function prototypes *** */
void main(int argc, char *argv[]);
void btd4x4(FILE *fp1, FILE * fp2);
int GetCode(byte *a, byte *b, word * code, FILE *fp);
int PutBlock(byte *block, FILE *fp);
void inform(char *mess);
void main(int argc, char *argv[])
{
/* A diver routine for "btd4x4.c", that decompresses a block truncation
** compressed file. */
FILE *fp1,*fp2;
if (argc < 3){
inform("Usage: BTD4x4 infile outfile\n\n");
inform("infile is a BTC-compressed file\n");
inform("outfile is a 256x256 binary image file\n");
exit(-1);
}
if ((fp1 = fopen(argv[1],"rb")) == NULL) {
inform("ERROR: Could not open input file: ");
inform(argv[1]);
exit(-1);
}
setvbuf(fp1,(char *)NULL,_IOFBF,IOBUFFSIZE);
if ((fp2 = fopen(argv[2],"wb")) == NULL) {
inform("ERROR: Could not open output file: ");
inform(argv[2]);
exit(-1);
}
setvbuf(fp2,(char *)NULL,_IOFBF,IOBUFFSIZE);
inform("Block Truncation Decompression.\n");
inform(argv[1]); inform(" -> "); inform(argv[2]);
inform("\nPlease wait...\n");
btd4x4(fp1, fp2);
fclose(fp1);
fclose(fp2);
inform("Done!\n");
exit(0);
}
void btd4x4(FILE *fp1, FILE * fp2)
{
/* Decompress the block truncation compressed file connected to "fp1".
** The output goes to the file connected to "fp2". */
int i;
byte a,b;
byte block[16];
word code;
while (GetCode(&a,&b,&code,fp1) != EOF){
for (i=0;i<=15;i++)
if (code & (1 << i)) /* is bit "i" set ? */
block[i] = b;
else
block[i] = a;
PutBlock(block,fp2);
}
/* The 4-line buffer maintained by "PutBlock" should be full at this point.
** Output one last dummy block. This will not be written to the output
** file, and only serves to flush that buffer. */
PutBlock(block,fp2);
}
int PutBlock(byte *block, FILE *fp)
{
/* This routine writes a block of 4x4 pixels to the file connected to "fp".
** Normally it returns 1. If at EOF, or errors occur, it returns EOF. */
static int bp = 0;
static byte buffer[4][256];
int i,j;
/* If the 4-line buffer is full, flush it. If it cannot be flushed for some
** reason, return EOF. Otherwise, reset the buffer pointer "bp". */
if (bp == 256){
for (j=0;j<=3;j++)
if (fwrite(buffer[j],1,256,fp) != 256)
return(EOF);
bp = 0;
}
/* Place 16 pixels in the 4-line buffer. Then update the buffer pointer
** "bp", and return to caller. */
for (j=0;j<=3;j++)
for (i=0;i<=3;i++)
buffer[j][bp+i] = block[i+4*j];
bp = bp+4;
return(1);
}
int GetCode(byte *a, byte *b, word * code, FILE *fp)
{
/* This routine gets "a", "b", and the block truncation "code" from the
** file connected to "fp". Normally it returns 1. If at end of file, or
** errors occur, it returns EOF. */
*a = (byte)fgetc(fp);
*b = (byte)fgetc(fp);
*code = fgetc(fp); /* LSB first */
*code = (fgetc(fp) << 8) + *code; /* MSB second */
if (feof(fp) || ferror(fp))
return(EOF);
else
return(1);
}
void inform(char *mess)
{
fprintf(stderr,"%s",mess);
}